﻿using PLCLib.Interface;
using PLCLib.Model;
using System;

namespace PlcLib.Model
{
    /// <summary>
    /// 欧姆龙读写返回结果实体
    /// </summary>
    public class OrmonResult : IPlcResult
    {
        public Command Command { get; set; }

        public object Content { get; set; }

        public bool Success { get; set; }

        public string Message { get; set; }

        public Exception Exception { get; set; }

        public byte[] ReceiveBuffer { get; set; }
    }


    /// <summary>
    /// 欧姆龙读写返回结果实体(泛型)
    /// </summary>
    public class OrmonResult<T> : IPlcResult<T>
    {
        public Command Command { get; set; }

        /// <summary>
        /// 返回数据（bool byte short  short[]  ushort ushort[]  int int[]  uint uint[] float float[] double double[]）
        /// </summary>
        public T Content
        {
            get
            {
                object result = new object();

                if (RealByteArray.Length == 0)
                {
                    throw new Exception("获取回复数据部分失败");
                }

                var type = typeof(T);
                switch (type.FullName)
                {
                    //单个变量
                    case "System.Boolean":
                        result = GetBoolean(RealByteArray);
                        break;
                    case "System.Byte":
                        result = GetByte(RealByteArray);
                        break;
                    case "System.Single":
                        result = GetSingle(RealByteArray);
                        break;
                    case "System.Int16":
                        result = GetInt16(RealByteArray);
                        break;
                    case "System.UInt16":
                        result = GetUInit16(RealByteArray);
                        break;
                    case "System.Int32":
                        result = GetInt32(RealByteArray);
                        break;
                    case "System.UInt32":
                        result = GetUInt32(RealByteArray);
                        break;

                    //数组
                    case "System.Byte[]":
                        result = GetByteArray(RealByteArray);
                        break;
                    case "System.Single[]":
                        result = GetSingleArray(RealByteArray);
                        break;
                    case "System.Int16[]":
                        result = GetInt16Array(RealByteArray);
                        break;
                    case "System.UInt16[]":
                        result = GetUInt16Array(RealByteArray);
                        break;
                    case "System.Int32[]":
                        result = GetInt32Array(RealByteArray);
                        break;
                    case "System.UInt32[]":
                        result = GetUInt32Array(RealByteArray);
                        break;
                }


                return (T)result;
            }
        }

        private object GetUInt32Array(byte[] realByteArray)
        {
            if (realByteArray.Length == 0)
            {
                throw new Exception("转换Int32数组长度为零");
            }

            if (realByteArray.Length != Command.Length * 2)
            {
                throw new Exception("转换Int32数组长度不符合要求");
            }

            uint[] result = new uint[realByteArray.Length / 4];//int占4字节
            switch (Command.DataType)
            {
                case CommunicaionLib.Enums.DataType.Bit:
                    break;
                case CommunicaionLib.Enums.DataType.WordHEX:
                    for (int i = 0; i < realByteArray.Length; i += 4)
                    {
                        //高低位转换
                        byte[] array = new byte[4];
                        array[0] = realByteArray[i + 1];
                        array[1] = realByteArray[i + 0];
                        array[2] = realByteArray[i + 3];
                        array[3] = realByteArray[i + 2];
                        uint number = BitConverter.ToUInt32(array, 0);
                        result[i / 4] = number;
                    }
                    break;
                case CommunicaionLib.Enums.DataType.WordBCD:
                    break;
                default:
                    break;
            }

            return result;
        }

        private object GetInt32Array(byte[] realByteArray)
        {
            if (realByteArray.Length == 0)
            {
                throw new Exception("转换Int32数组长度为零");
            }

            if (realByteArray.Length != Command.Length * 2)
            {
                throw new Exception("转换Int32数组长度不符合要求");
            }

            int[] result = new int[realByteArray.Length / 4];//int占4字节
            switch (Command.DataType)
            {
                case CommunicaionLib.Enums.DataType.Bit:
                    break;
                case CommunicaionLib.Enums.DataType.WordHEX:
                    for (int i = 0; i < realByteArray.Length; i += 4)
                    {
                        //高低位转换
                        byte[] array = new byte[4];
                        array[0] = realByteArray[i + 1];
                        array[1] = realByteArray[i + 0];
                        array[2] = realByteArray[i + 3];
                        array[3] = realByteArray[i + 2];
                        int number = BitConverter.ToInt32(array, 0);
                        result[i / 4] = number;
                    }
                    break;
                case CommunicaionLib.Enums.DataType.WordBCD:
                    break;
                default:
                    break;
            }

            return result;
        }

        private object GetUInt16Array(byte[] realByteArray)
        {
            if (realByteArray.Length == 0)
            {
                throw new Exception("转换UInt16数组长度为零");
            }

            if (realByteArray.Length != Command.Length * 2)
            {
                throw new Exception("转换UInt16数组长度不符合要求");
            }

            ushort[] result = new ushort[Command.Length];//ushort占两个字节，2字节=1个字长
            switch (Command.DataType)
            {
                case CommunicaionLib.Enums.DataType.Bit:
                    break;
                case CommunicaionLib.Enums.DataType.WordHEX:
                    for (int i = 0; i < realByteArray.Length; i += 2)
                    {
                        result[i / 2] = (ushort)((realByteArray[i] << 8) + realByteArray[i + 1]);
                    }
                    break;
                case CommunicaionLib.Enums.DataType.WordBCD:
                    break;
                default:
                    break;
            }

            return result;
        }

        private object GetInt16Array(byte[] realByteArray)
        {
            if (realByteArray.Length == 0)
            {
                throw new Exception("转换Int16数组长度为零");
            }

            if (realByteArray.Length != Command.Length * 2)
            {
                throw new Exception("转换Int16数组长度不符合要求");
            }

            short[] result = new short[Command.Length];//short占两个字节，2字节=1个字长
            switch (Command.DataType)
            {
                case CommunicaionLib.Enums.DataType.Bit:
                    break;
                case CommunicaionLib.Enums.DataType.WordHEX:
                    for (int i = 0; i < realByteArray.Length; i += 2)
                    {
                        result[i / 2] = (short)((realByteArray[i] << 8) + realByteArray[i + 1]);
                    }
                    break;
                case CommunicaionLib.Enums.DataType.WordBCD:
                    break;
                default:
                    break;
            }

            return result;
        }

        private object GetSingleArray(byte[] realByteArray)
        {
            if (realByteArray.Length == 0)
            {
                throw new Exception("转换System.Single[]数组长度为零");
            }

            if (realByteArray.Length != Command.Length * 2)
            {
                throw new Exception("转换System.Single[]数组长度不符合要求");
            }

            float[] result = new float[realByteArray.Length / 4];//float占4字节
            switch (Command.DataType)
            {
                case CommunicaionLib.Enums.DataType.Bit:
                    break;
                case CommunicaionLib.Enums.DataType.WordHEX:
                    for (int i = 0; i < realByteArray.Length; i += 4)
                    {
                        //高低位转换
                        byte[] array = new byte[4];
                        array[0] = realByteArray[i + 1];
                        array[1] = realByteArray[i + 0];
                        array[2] = realByteArray[i + 3];
                        array[3] = realByteArray[i + 2];
                        float number = BitConverter.ToSingle(array, 0);
                        result[i / 4] = number;
                    }
                    break;
                case CommunicaionLib.Enums.DataType.WordBCD:
                    break;
                default:
                    break;
            }

            return result;
        }

        private object GetByteArray(byte[] realByteArray)
        {
            return realByteArray;
        }

        private object GetUInt32(byte[] realByteArray)
        {
            if (realByteArray.Length != 4)
            {
                throw new Exception("错误:转换UInt32时需要4个字节");
            }

            //高低位转换
            for (int i = 0; i < realByteArray.Length; i = i + 2)
            {
                byte temp = realByteArray[i];
                realByteArray[i] = realByteArray[i + 1];
                realByteArray[i + 1] = temp;

            }
            object result = BitConverter.ToUInt32(realByteArray, 0);
            return result;
        }

        private object GetInt32(byte[] realByteArray)
        {
            if (realByteArray.Length != 4)
            {
                throw new Exception("错误:转换Int32时需要4个字节");
            }

            //高低位转换
            for (int i = 0; i < realByteArray.Length; i = i + 2)
            {
                byte temp = realByteArray[i];
                realByteArray[i] = realByteArray[i + 1];
                realByteArray[i + 1] = temp;

            }
            object result = BitConverter.ToInt32(realByteArray, 0);
            return result;
        }

        private object GetUInit16(byte[] realByteArray)
        {
            if (realByteArray.Length != 2)
            {
                throw new Exception("错误:转换UInt16时需要2个字节");
            }

            for (int i = 0; i < realByteArray.Length; i += 2)
            {
                byte temp = realByteArray[i];
                realByteArray[i] = realByteArray[i + 1];
                realByteArray[i + 1] = temp;
            }

            ushort result = BitConverter.ToUInt16(realByteArray, 0);
            return result;
        }

        private object GetInt16(byte[] realByteArray)
        {
            if (realByteArray.Length != 2)
            {
                throw new Exception("错误:转换Int16时需要2个字节");
            }

            for (int i = 0; i < realByteArray.Length; i += 2)
            {
                byte temp = realByteArray[i];
                realByteArray[i] = realByteArray[i + 1];
                realByteArray[i + 1] = temp;
            }

            short result = BitConverter.ToInt16(realByteArray, 0);
            return result;
        }

        private object GetSingle(byte[] realByteArray)
        {
            if (realByteArray.Length == 0)
            {
                throw new Exception("转换System.Single数组长度为零");
            }

            if (realByteArray.Length != 4)
            {
                throw new Exception("转换System.Single数组长度不符合要求");
            }

            //高低位转换
            byte[] array = new byte[4];
            array[0] = realByteArray[1];
            array[1] = realByteArray[0];
            array[2] = realByteArray[3];
            array[3] = realByteArray[2];
            float number = BitConverter.ToSingle(array, 0);
            return number;
        }

        private object GetByte(byte[] realByteArray)
        {
            if (realByteArray.Length != 2)
            {
                throw new Exception("错误:转换Byte时需要1个字节");
            }

            return realByteArray[1];
        }

        private object GetBoolean(byte[] realByteArray)
        {
            bool result = new bool();
            if (realByteArray.Length == 0)
            {
                throw new Exception("错误:转换Boolean时需要1个字节");
            }

            if (Command.DataType == CommunicaionLib.Enums.DataType.Bit)
            {
                result = realByteArray[0] != 0;
            }

            return result;
        }

        public bool Success { get; set; }

        public string Message { get; set; }

        public Exception Exception { get; set; }

        public byte[] ReceiveBuffer { get; set; }


        /// <summary>
        /// 获取读取PLC返回的数据部分
        /// </summary>
        public byte[] RealByteArray
        {
            get
            {
                //判断空对象
                if (ReceiveBuffer == null)
                {
                    return new byte[0];
                }

                //判断指令基础长度
                if (ReceiveBuffer.Length < 30)
                {
                    return new byte[0];
                }

                //判断指令头部 46 49 4E 53
                if (ReceiveBuffer[0] != 0x46 || ReceiveBuffer[1] != 0x49 || ReceiveBuffer[2] != 0x4E || ReceiveBuffer[3] != 0x53)
                {
                    return new byte[0];
                }

                //判断指令错误码
                if (ReceiveBuffer[28] != 0x00 || ReceiveBuffer[29] != 0x00)
                {
                    return new byte[0];
                }

                //判断指令总长度
                if (ReceiveBuffer[7] + 8 != ReceiveBuffer.Length)
                {
                    return new byte[0];
                }

                //判断读写指令的回复数据
                if (ReceiveBuffer[26] == 0x01 || ReceiveBuffer[27] == 0x01)
                {
                    //截取数据部分
                    var length = ReceiveBuffer.Length - 30;
                    var result = new byte[length];
                    Array.Copy(ReceiveBuffer, 30, result, 0, length);
                    return result;
                }
                else if (ReceiveBuffer[26] == 0x01 || ReceiveBuffer[27] == 0x02)
                {
                    //todo  截取写指令
                }
                else
                {
                    return new byte[0];
                }


                return new byte[0];
            }
        }
    }
}
